//
// Created by 周杰 on 2020/1/14.
//

#include "RiceDetectTest.h"

const string image_path = "/Volumes/D/study/machinelearning/opencv/testpic/mi.png";

/**
 * cnts size: 89
rice avg area: 194.803371
rice avg length: 25.977528
rice length variance: 49.550057
rice length sdv: 7.039180
rice area variance: 4894.902348
rice area sdv: 69.963579
sdv rice count: 87

 */
void RiceDetectTest::riceTest() {
    Mat source_image = imread(image_path);
    imshow("source image.", source_image);

    //将图片转换成灰度图片
    Mat gray_image;
    cvtColor(source_image, gray_image, COLOR_BGR2GRAY);
    imshow("gray image.", gray_image);

    //进行高斯滤波，去除部分噪声
    Mat gaussian_image;
    GaussianBlur(gray_image, gaussian_image, Size(3, 3), 0);
    imshow("gaussian image.", gaussian_image);

    //通过自适应法制化进行图片分割
    Mat adapt_image;
    //块大小一定要为奇数  adaptiveMethod里边有两个，一个是高斯加权平均减去C一个是平均减去C,设置块大小35所有米粒都分开了
    adaptiveThreshold(gaussian_image, adapt_image, 0xff, AdaptiveThresholdTypes::ADAPTIVE_THRESH_MEAN_C,
                      ThresholdTypes::THRESH_BINARY, 35, 0);
    imshow("adapt image.", adapt_image);
    //寻找边界
    Mat seg = adapt_image.clone();
    //找到的区域
    vector<vector<Point>> cnts;
    //仅仅进行外部轮廓检索
    findContours(seg, cnts, RetrievalModes::RETR_EXTERNAL, ContourApproximationModes::CHAIN_APPROX_SIMPLE);
    //米粒数量
    int count = 0;
    //米粒总面积
    double areas = 0;
    //选取米粒两边最大值的那个作为米粒长度
    double lengths;
    //保存米粒的每一个的长度
    vector<double> v_length;
    //保存米粒的面积
    vector<double> v_area;
    for (int i = 0; i < cnts.size(); ++i) {
        vector<Point> vRs = cnts[i];
        //初略计算米粒面积
        double area = contourArea(vRs);

        //跳过区域小于50的米粒
        if (area < 50.0) {
            continue;
        }

        v_area.push_back(area);
        count++;
        printf("count %d  area: %lf \n", count,area);

        areas += area;
        //获取矩形边界
        Rect rect = boundingRect(vRs);
        //在原图像上绘制红色矩形框
        rectangle(source_image, rect, Scalar(0, 0, 255));

        double length = 0;
        if (rect.width > rect.height) {
            length = rect.width;
        } else {
            length = rect.height;
        }
        lengths += length;
        v_length.push_back(length);

        //给米粒编号
        const string rice_count = to_string(count);
        //给米粒绘制上编号
        putText(source_image, rice_count, Point(rect.x, rect.y), HersheyFonts::FONT_HERSHEY_PLAIN, 0.8,
                Scalar(0, 0, 255));
    }
    printf("cnts size: %d \n", count);
    imshow("result", source_image);

    //米粒的平均面积
    double avg_area = areas / count;
    printf("rice avg area: %lf \n", avg_area);

    //米粒的平均长度
    double avg_length = lengths / count;
    printf("rice avg length: %lf \n", avg_length);
    double pows;
    for (int j = 0; j < v_length.size(); ++j) {
        double length = v_length[j];
        double powL = pow((length - avg_length), 2);
        pows += powL;
    }

    //方差
    double rice_length_variance = pows / count;
    printf("rice length variance: %lf \n", rice_length_variance);

    //标准差
    double rice_length_sdv = sqrt(rice_length_variance);
    printf("rice length sdv: %lf \n", rice_length_sdv);

    double area_pows;
    for (int k = 0; k < v_area.size(); ++k) {
        double area = v_area[k];
        double powA = pow((area - avg_area), 2);
        area_pows += powA;
    }

    //面积方差
    double rice_area_variance = area_pows / count;
    printf("rice area variance: %lf \n", rice_area_variance);
    //面积标准差
    double rice_area_sdv = sqrt(rice_area_variance);
    printf("rice area sdv: %lf \n", rice_area_sdv);

    //分析  米粒大小在3sigma (3个标准差下是否有多少米粒)，就是排除 米粒大小 大于3sigma或者小于3sigma的米粒
    int s_count = 0;
    for (int l = 0; l < v_area.size(); ++l) {
        double area = v_area[l];
        //这里是用真实值减去均值然后再和3倍标准差比较
        if (abs(area - avg_area) <= 3 * rice_area_sdv) {
            s_count++;
        }
    }
    printf("sdv rice count: %d \n", s_count);

    waitKey();
    destroyAllWindows();

}